package com.rkc.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.rkc.config.RabbitMQConfiguration;
import com.rkc.enums.BizCodeEnum;
import com.rkc.enums.ProductOrderStateEnum;
import com.rkc.enums.StockTaskStateEnum;
import com.rkc.exception.BizException;
import com.rkc.feign.ProductOrderFeignService;
import com.rkc.mapper.ProductMapper;
import com.rkc.mapper.ProductTaskMapper;
import com.rkc.model.ProductDO;
import com.rkc.model.ProductMessage;
import com.rkc.model.ProductTaskDO;
import com.rkc.request.LockProductRequest;
import com.rkc.request.OrderItemRequest;
import com.rkc.service.ProductService;
import com.rkc.utils.JsonData;
import com.rkc.vo.ProductVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 冉堃赤
 * @since 2021-10-28
 */
@Slf4j
@Service
public class ProductServiceImpl implements ProductService {

    @Resource
    private ProductMapper productMapper;

    @Resource
    private ProductTaskMapper productTaskMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RabbitMQConfiguration rabbitMQConfiguration;

    @Autowired
    private ProductOrderFeignService productOrderFeignService;

    @Override
    public Map<String, Object> page(int page, int size) {
        Page<ProductDO> pageInfo = new Page<>(page, size);
        Page<ProductDO> productDOPage = productMapper.selectPage(pageInfo, null);
        Map<String, Object> pageMap = new HashMap<>(3);
        pageMap.put("total_record", productDOPage.getTotal());
        pageMap.put("total_page", productDOPage.getPages());
        pageMap.put("current_data", productDOPage.getRecords().stream().map(this::beanProcess).collect(Collectors.toList()));
        return pageMap;
    }

    /**
     * 根据id查询商品
     * @param productId id
     * @return
     */
    @Override
    public ProductVO detailById(long productId) {
        ProductDO productDO = productMapper.selectById(productId);
        return beanProcess(productDO);
    }

    /**
     * 批量查询
     * @param productIdList
     * @return
     */
    @Override
    public List<ProductVO> findProductsByIdBatch(List<Long> productIdList) {
        List<ProductDO> productDOList = productMapper.selectList(new QueryWrapper<ProductDO>().in("id", productIdList));
        return productDOList.stream().map(this::beanProcess).collect(Collectors.toList());
    }

    /**
     * 锁定商品库存
     * 1）遍历商品，锁定每个商品购买数量
     * 2）每一次锁定都要发送延时消息
     * @param lockProductRequest
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public JsonData lockProductStock(LockProductRequest lockProductRequest) {
        String orderOutTradeNo = lockProductRequest.getOrderOutTradeNo();
        List<OrderItemRequest> orderItemList = lockProductRequest.getOrderItemList();
        List<Long> idList = orderItemList.stream().map(OrderItemRequest::getProductId).collect(Collectors.toList());

        List<ProductVO> productVOList = findProductsByIdBatch(idList);
        //流根据id进行分组转化为map
        Map<Long, ProductVO> idToProduct = productVOList.stream().collect(Collectors.toMap(ProductVO::getId, Function.identity()));

        for (OrderItemRequest itemRequest : orderItemList) {
            //锁定商品记录
            int row = productMapper.lockProductStock(itemRequest.getProductId(), itemRequest.getBuyNum());
            if (row != 1) {
                throw new BizException(BizCodeEnum.ORDER_CONFIRM_LOCK_PRODUCT_FAIL);
            }
            //插入product_task并发送延时消息
            ProductVO productVO = idToProduct.get(itemRequest.getProductId());
            ProductTaskDO productTaskDO = new ProductTaskDO();
            productTaskDO.setBuyNum(itemRequest.getBuyNum());
            productTaskDO.setLockState(StockTaskStateEnum.LOCK.name());
            productTaskDO.setProductId(itemRequest.getProductId());
            productTaskDO.setProductName(productVO.getTitle());
            productTaskDO.setOutTradeNo(orderOutTradeNo);
            log.info("商品库存锁定插入成功:{}", productTaskDO);

            //插入task表
            productTaskMapper.insert(productTaskDO);
            //发送延时消息
            ProductMessage productMessage = new ProductMessage();
            productMessage.setOutTradeNo(orderOutTradeNo);
            productMessage.setTaskId(productTaskDO.getId());
            rabbitTemplate.convertAndSend(rabbitMQConfiguration.getEventExchange(), rabbitMQConfiguration.getStockReleaseDelayRoutingKey(), productMessage);
            log.info("商品库存锁定信息延迟消息发送成功:{}", productMessage);
        }
        return JsonData.buildSuccess();
    }

    /**
     * 释放商品库存
     * @param productMessage
     * @return
     */
    @Override
    public boolean releaseProductStock(ProductMessage productMessage) {
        //查询工作单状态
        ProductTaskDO productTaskDO = productTaskMapper.selectById(productMessage.getTaskId());
        if (productTaskDO == null) {
            log.warn("工作单不存在 {}", productMessage);
            return true;
        }
        //只处理lock状态
        if (productTaskDO.getLockState().equalsIgnoreCase(StockTaskStateEnum.LOCK.name())) {
            JsonData res = productOrderFeignService.queryProductOrderState(productMessage.getOutTradeNo());
            if (res.getCode() == 0) {
                //正常响应，判断订单状态
                String state = res.getData().toString();
                if (ProductOrderStateEnum.NEW.name().equalsIgnoreCase(state)) {
                    //状态还是NEW，返回消息队列，重新处理，正常情况是不会走到这的
                    log.warn("订单状态是NEW，返回消息队列，重新投递：{}", productMessage);
                    return false;
                }
                if (ProductOrderStateEnum.PAY.name().equalsIgnoreCase(state)) {
                    //已经支付的订单，修改task状态为FINISH
                    productTaskDO.setLockState(StockTaskStateEnum.FINISH.name());
                    productTaskMapper.updateById(productTaskDO);
                    log.info("订单已经支付，修改库存锁定工作单为FINISH状态：{}", productMessage);
                    return true;
                }
            }
            //订单不存在
            log.warn("订单被取消或删除，确认消息，修改task状态为CANCEL，恢复商品库存，message：{}", productMessage);
            //将锁状态改为取消
            productTaskDO.setLockState(StockTaskStateEnum.CANCEL.name());
            productTaskMapper.updateById(productTaskDO);
            //恢复商品库存
            productMapper.unlockProductStock(productTaskDO.getProductId(), productTaskDO.getBuyNum());
            return true;
        }
        log.warn("工作单不是lock状态 {}", productMessage);
        productTaskDO.setLockState(StockTaskStateEnum.CANCEL.name());
        productTaskMapper.updateById(productTaskDO);
        return true;
    }

    private ProductVO beanProcess(ProductDO productDO) {
        ProductVO productVO = new ProductVO();
        BeanUtils.copyProperties(productDO, productVO);
        //展示出的剩余库存=库存-被用户锁定的库存
        productVO.setStock(productDO.getStock() - productDO.getLockStock());
        return productVO;
    }
}
